﻿//==============================================================================
// File: StatusManager.cs
// Created: 2010-05-28
// Author: Arkadiusz Świerczek
//==============================================================================
// This file is a part of MAMMOTH project.
// Copyright (C) 2010 AGH University of Science and Technology, Krakow.
// https://caribou.iisg.agh.edu.pl/trac/mammoth
//
// Mammoth is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// Mammoth is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public License
// along with Mammoth. If not, see http://www.gnu.org/licenses/.
//==============================================================================

using System;
using System.Windows.Input;
using WpfRcp.Core.Services;
using WpfRcp.Core.Services.Status;
using WpfRcp.Core.Threading;
using WpfRcp.Core.Views;
using WpfRcp.Core.Views.Presenters;
using WpfRcp.Services.Status;

namespace WpfRcp.Services
{
    public class StatusManager : IStatusManager
    {
        private readonly StatusViewPresentationModel m_StatusViewPresentationModel;
        private ProgressViewPresentationModel m_CurrentProgressViewPresentationModel;

        public StatusManager(StatusViewPresentationModel statusViewPresentationModel)
        {
            m_StatusViewPresentationModel = statusViewPresentationModel;
        }

        public IDisposable CreateWaitCursor()
        {
            var monitor = new BusyCursorMonitor();
            return monitor;
        }

        public ISimpleRcpStatusMonitor CreateSimpleStatusMonitor(string taskName, Job job, IProgressView progressView)
        {
            var monitor = new SimpleRcpStatusMonitor();
            InitializeJob(job, monitor, progressView);
            InitializeMonitor(monitor, taskName, job.Options.IsBackgroundable, job.Options.IsCancelable, job.Cancel, progressView);
            return monitor;
        }

        public ISimpleRcpStatusMonitor CreateSimpleStatusMonitor(string taskName, bool isBackgroundable, bool isCancelable, Action cancelAction, IProgressView progressView)
        {
            var monitor = new SimpleRcpStatusMonitor();
            InitializeMonitor(monitor, taskName, isBackgroundable, isCancelable, cancelAction, progressView);
            return monitor;
        }

        public IRcpStatusMonitor CreateStatusMonitor(string taskName, Job job, IProgressView progressView)
        {
            var monitor = new RcpStatusMonitor();
            InitializeJob(job, monitor, progressView);
            InitializeMonitor(monitor, taskName, job.Options.IsBackgroundable, job.Options.IsCancelable, job.Cancel, progressView);
            return monitor;
        }

        public IRcpStatusMonitor CreateStatusMonitor(string taskName, bool isBackgroundable, bool isCancelable, Action cancelAction, IProgressView progressView)
        {
            var monitor = new RcpStatusMonitor();
            InitializeMonitor(monitor, taskName, isBackgroundable, isCancelable, cancelAction, progressView);
            return monitor;
        }

        private class BusyCursorMonitor : IDisposable
        {
            private readonly Cursor m_OldCursor;

            public BusyCursorMonitor()
            {
                m_OldCursor = Mouse.OverrideCursor;
                Mouse.OverrideCursor = Cursors.Wait;
            }

            public void Dispose()
            {
                Mouse.OverrideCursor = m_OldCursor;
            }
        }

        private void InitializeMonitor(SimpleRcpStatusMonitor monitor, string taskName, bool isBackgroundable, bool isCancelable, Action cancelAction, IProgressView progressView)
        {
            if (m_CurrentProgressViewPresentationModel != null)
            {
                throw new InvalidOperationException("There should be only one foreground monitor.");
            }

            monitor.TaskName = taskName;
            monitor.Cancelable = isCancelable;
            monitor.Backgroundable = isBackgroundable;
            monitor.Disposed += ClearProgressMonitor;
            monitor.Canceled += (sender, e) => cancelAction();
            monitor.SentToBackground += (sender, e) =>
            {
                ClearProgressMonitor(null, null);
                m_StatusViewPresentationModel.Monitors.Add(monitor);
                monitor.Disposed -= ClearProgressMonitor;
                monitor.Disposed += (s, ev) => m_StatusViewPresentationModel.Monitors.Remove(monitor);
            };

            m_CurrentProgressViewPresentationModel = new ProgressViewPresentationModel(progressView)
            {
                Monitor = monitor
            };
        }

        private void ClearProgressMonitor(object sender, EventArgs e)
        {
            m_CurrentProgressViewPresentationModel.Dispose();
            m_CurrentProgressViewPresentationModel = null;
        }

        private static void InitializeJob(Job job, SimpleRcpStatusMonitor monitor, IProgressView progressView)
        {
            EventHandler<EventArgs> handler = (sender, e) =>
            {
                monitor.Dispose();
                if (progressView is IWindowedProgressView)
                    ((IWindowedProgressView)progressView).Close();
            };
            job.Error += (sender, e) => handler(sender, e);
            job.Completed += handler;
            job.Cancelled += handler;
        }
    }
}